package com.markby.fscm.cryptogram.domain.standard0018;

import java.nio.ByteOrder;

import static com.markby.fscm.cryptogram.domain.standard0018.Constant0018.ECCref_MAX_LEN;
import static com.markby.fscm.cryptogram.uitls.HexUtils.intToBytes;


/**
 * 0018-2023规范 ECC密钥对保护数据结构
 * ULONG 为32位无符号整数
 * typedef struct EnvelopedECCKey_st{
 * ULONG Version;                               // 版本号，本版本为1(4字节)
 * ULONG ulSymmAlgID;                           // 对称算法标识(必须为ECB模式)(4字节)
 * ULONG ulBits;                                // ECC密钥对的密钥位长(4字节)
 * BYTE cbEncryptedPriKey[ECCref_MAX_LEN];      // 对称算法加密的ECC私钥，ECC需要的原文为ECCrefPrivateKey结构中的K，其有效长度为原文的(ulBits+7)/8
 * ECCrefPublicKey PubKey;                      // ECC密钥对的公钥(ECCref_MAX_LEN*2+4字节)
 * ECCCipher ECCCipherBlob;                     // 用保护公钥加密过的对称密钥密文结构(ECCref_MAX_LEN*2+32+4+L字节)
 * }EnvelopedECCKey;
 * 私钥密文结构中有效密文分组从0偏移量字节开始,顺序解密密文分组后将明文连接得到ECC密钥对的私钥的明文。
 */
public class EnvelopedECCKey {

    private int Version;
    private int ulSymmAlgID;
    private int ulBits;
    private byte[] cbEncryptedPriKey;
    private ECCrefPublicKey PubKey;
    private ECCCipher ECCCipherBlob;

    public EnvelopedECCKey(int ulSymmAlgID, int ulBits, byte[] cbEncryptedPriKey, ECCrefPublicKey PubKey, ECCCipher ECCCipherBlob) {
        this(1, ulSymmAlgID, ulBits, cbEncryptedPriKey, PubKey, ECCCipherBlob);
    }

    public EnvelopedECCKey(int version, int ulSymmAlgID, int ulBits, byte[] cbEncryptedPriKey, ECCrefPublicKey PubKey, ECCCipher ECCCipherBlob) {
        if (cbEncryptedPriKey.length != ECCref_MAX_LEN) {
            throw new IllegalArgumentException("Invalid cbEncryptedPriKey length: " + cbEncryptedPriKey.length);
        }
        if (PubKey.getBytes().length != (ECCref_MAX_LEN * 2 + 4)) {
            throw new IllegalArgumentException("Invalid PubKey length: " + PubKey.getBytes().length);
        }
        if (ECCCipherBlob.getBytes().length != (ECCref_MAX_LEN * 2 + 32 + 4 + ECCCipherBlob.getL())) {
            throw new IllegalArgumentException("Invalid ECCCipherBlob length: " + ECCCipherBlob.getBytes().length);
        }
        this.Version = version;
        this.ulSymmAlgID = ulSymmAlgID;
        this.ulBits = ulBits;
        this.cbEncryptedPriKey = cbEncryptedPriKey;
        this.PubKey = PubKey;
        this.ECCCipherBlob = ECCCipherBlob;
    }

    public byte[] getBytes() {
        byte[] versionBytes = intToBytes(Version, ByteOrder.LITTLE_ENDIAN);
        byte[] ulSymmAlgIDBytes = intToBytes(ulSymmAlgID, ByteOrder.LITTLE_ENDIAN);
        byte[] ulBitsBytes = intToBytes(ulBits, ByteOrder.LITTLE_ENDIAN);
        byte[] cbEncryptedPriKeyBytes = cbEncryptedPriKey;
        byte[] PubKeyBytes = PubKey.getBytes();
        byte[] ECCCipherBlobBytes = ECCCipherBlob.getBytes();
        byte[] result = new byte[versionBytes.length + ulSymmAlgIDBytes.length + ulBitsBytes.length + cbEncryptedPriKeyBytes.length + PubKeyBytes.length + ECCCipherBlobBytes.length];
        System.arraycopy(versionBytes, 0, result, 0, versionBytes.length);
        System.arraycopy(ulSymmAlgIDBytes, 0, result, versionBytes.length, ulSymmAlgIDBytes.length);
        System.arraycopy(ulBitsBytes, 0, result, versionBytes.length + ulSymmAlgIDBytes.length, ulBitsBytes.length);
        System.arraycopy(cbEncryptedPriKeyBytes, 0, result, versionBytes.length + ulSymmAlgIDBytes.length + ulBitsBytes.length, cbEncryptedPriKeyBytes.length);
        System.arraycopy(PubKeyBytes, 0, result, versionBytes.length + ulSymmAlgIDBytes.length + ulBitsBytes.length + cbEncryptedPriKeyBytes.length, PubKeyBytes.length);
        System.arraycopy(ECCCipherBlobBytes, 0, result, versionBytes.length + ulSymmAlgIDBytes.length + ulBitsBytes.length + cbEncryptedPriKeyBytes.length + PubKeyBytes.length, ECCCipherBlobBytes.length);
        return result;
    }
}
